#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <strings.h>

#define SERV_PORT    8000
#define MAXLEN       4096

typedef struct sockaddr SA;

static int Socket(int domain, int type, int protocol);
static int Bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
static ssize_t Recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
static ssize_t Sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
static void dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen);


int main()
{
    int sockfd;
    struct sockaddr_in servaddr, cliaddr;

    sockfd = Socket(AF_INET, SOCK_DGRAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    Bind(sockfd, (SA *)&servaddr, sizeof(servaddr));

    dg_echo(sockfd, (SA *) &cliaddr, sizeof(cliaddr));

    return 0;
}

static void dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen)
{
    int n;
    socklen_t len;
    char mesg[MAXLEN];

    for (; ;) {
        len = clilen;
        n = Recvfrom(sockfd, mesg, MAXLEN, 0, pcliaddr, &len);

        Sendto(sockfd, mesg, n, 0, pcliaddr, len);
    }
}


static ssize_t Recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
{
    int ret = recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
    if (ret < 0) {
        perror("recvfrom error");
        exit(1);
    }

    return ret;
}


static ssize_t Sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
{
    int ret = sendto(sockfd, buf, len, flags, dest_addr, addrlen);
    if (ret < 0) {
        perror("sendto error");
        exit(1);
    }

    return ret;
}


static int Socket(int domain, int type, int protocol) 
{
    int fd = socket(domain, type, protocol);
    if (fd < 0) {
        perror("socket error");
        exit(1);
    }

    return fd;
}

static int Bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
    int ret = bind(sockfd, addr, addrlen);
    if (ret < 0) {
        perror("bind error");
        exit(1);
    }

    return ret;
}


